//    Academic project for DOS, sorts numbers concurrently on 5 machines
//    Copyright (C) 2010  PRITHVI RAJ VENKAT RAJ
//
//       Licensed to the Apache Software Foundation (ASF) under one
//       or more contributor license agreements.  See the NOTICE file
//       distributed with this work for additional information
//       regarding copyright ownership.  The ASF licenses this file
//       to you under the Apache License, Version 2.0 (the
//       "License"); you may not use this file except in compliance
//       with the License.  You may obtain a copy of the License at
//
//         http://www.apache.org/licenses/LICENSE-2.0
//
//       Unless required by applicable law or agreed to in writing,
//       software distributed under the License is distributed on an
//       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//       KIND, either express or implied.  See the License for the
//       specific language governing permissions and limitations
//       under the License.


//Note: Will add code that will create 5 arrays dynamically after assigning numbers to the client machines
//the sorted arrays will also be stored in the same arrays.
//5 way merge will then arrange these in order


import java.util.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;





public class start extends Thread {

   private ServerSocket ss;
   private Connection c;
   int[][] testarray=new int[30][30];;
   int i=0,j=0;
   int[] tosort=new int[100];
	int[] sorted=new int[100];
	int[][] assigned=new int[5][];
	int[][] assigned_r=new int[5][];
	int[] length=new int[5];
	int[] cpuspeed=new int[20];
	int accepted_connections=0;
	boolean isAssigned=false; 
	int port=0;
	String ip=null;
	static Hashtable<String, Integer> client_table =new Hashtable<String, Integer>();
   
   
   
   
   public static void main(String argv[]) throws Exception {
	 start s=new start();
	 s.initServer();
	 s.initClient();
	 //int port=s.initServer();
     //System.out.println("Server listening on port:	"+port);
     //s.initClient(port,"127.0.0.1");
   }

   
   
   
	private void generateRandoms(){	
		Random generator=new Random();
		for(int i=0;i<100;i++)	
		tosort[i]=generator.nextInt(500);
		}

		

		
		
		private void assignRandoms(){
//		int[] cpuspeed={2,1,1,1,2};	
		float[] percentage=new float[5];
		int total=0;
		for(int i:cpuspeed) total+=i;
//		System.out.println("total is :"+total);
		for(int i=0;i<5;i++) {percentage[i]=Math.round((cpuspeed[i]*100/total));}
		total=0;
		for(float i:percentage) total+=i;
//		System.out.println("total percentage is :"+total);
		
		int diff=100-total;
		if(diff>0) percentage[2]+=diff;
		
		for(int i=0;i<5;i++) assigned[i]=new int[Math.round((percentage[i]))];
		int p=0;
		for(int i=0;i<5;i++)	
		{
			for(int j=0;j<percentage[i];j++)
			{	assigned[i][j]=tosort[p++];	
			}
		}


			
		isAssigned=true;	
		}
		
		
		private int calculateLength(){
			for(int i=0;i<5;i++)	
			{
				length[i]=assigned[i].length;
			}
			int total=0;
			for(int i:length) total+=i;
	        return total;
			
		}
		
		private void mergeArrays(){
			//naive algorithm, uses at least kn compares to merge
			int[] iterator=new int[5];
			
			int min=0,p=0;	
			
			while(min!=600)
			{
				
				min=600;
				int minxindex=0,minyindex=0;	
				for(int i=0;i<5;i++)
				{   
					if(min>assigned_r[i][iterator[i]]&&assigned_r[i][iterator[i]]<550) 
					{	min=assigned_r[i][iterator[i]];
					    minxindex=i;minyindex=iterator[i];
					}
					
				}
				if(minyindex+1<length[minxindex]) iterator[minxindex]++;
				assigned_r[minxindex][minyindex]=600;
				sorted[p]=min;
				
				System.out.print(sorted[p]+"\t");
				p++;
				if(p%20==0) System.out.println("");
				if(p==100) break;
								
	
			
			}
			
			}
		
   public void initClient() throws Exception{
	   for (int j=1;j < 6;j++)
	   {

	             try {
	                   String client = "lin114-0" + j + ".cise.ufl.edu";
	                   String path = System.getProperty("user.dir");
	                   
	                  System.out.println("\n Starting Remote Process: Client ID"+ j + " on" + client  );
	                  String a =  "ssh "+client + " ; cd " + path + " ; java Client" + " " + ip + " " + "ID" + j+ " " + port;
	                  System.out.println(a);
	                  Runtime.getRuntime().exec(a);
	                 System.out.println(" Status: SUCCESS! Parameters Passed:"+ ip +" "+ port + " "+ " ID"+j);

	                  } catch (Exception ex) {
	                 System.out.println(ex);
	             }
	    }	 
   }
   
   public void initServer() throws Exception {
	 
     ss = new ServerSocket(0);
     port=ss.getLocalPort();
// 		String ip=ss.
    // InetAddress ip=InetAddress.getLocalHost();
     ip=InetAddress.getLocalHost().getHostAddress();
     if(ip=="127.0.0.1"||ip=="0.0.0.0") 
     {
    	System.out.println("IP Address error");
    	System.exit(1);
     }
     System.out.println("Server : Listening on "+port+" and IP is "+ip);
     i=0;
     this.start();
     
   } 

   public void run() {
//	   System.out.println("NAME IS(ronout)  "+this.getId());
       
	   while(accepted_connections<5) {
       try {
    	accepted_connections++;
        System.out.println("Server: Waiting for connections.");
        Socket client = ss.accept();
        System.out.println("Server:	Accepted a connection from: "+client.getInetAddress());
        c = new Connection(client);
        cpuspeed[i]=c.getCpu();
//        System.out.println("Server:	Got CPUSP:"+cpuspeed[i]+"  Accepted conn:"+accepted_connections);
       } 
       
       catch(Exception e) {e.printStackTrace();}
     
       
       finally{
    	  
    	  
      }//end finally
     }//end while
	  
	   while(c.verifyThreads()){}
	   client_table=c.getHashtable();
	   System.out.println("Server	: CPU Speed mappings :"+client_table.toString());
	   for(i=1;i<6;i++){
	   cpuspeed[i-1]=client_table.get("ID"+i);   
//	   System.out.println("CPUSPEED "+i+" :"+cpuspeed[i-1]);
	   }
	   
	   
	   if(accepted_connections==5&&!isAssigned)
       {
			
		    generateRandoms();
			assignRandoms();
			calculateLength();

       System.out.println("Server:	All connections established");
       c.setArray(assigned);
       
       }
	   
	  
	   try {
		Thread.sleep(2000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
       
	
	
	   assigned_r=c.getArray();
       i++;  
//       for(int p=0;p<5;p++) 
//		{for(int k=0;k<assigned_r[p].length;k++)  
//		  System.out.print(assigned_r[p][k]+" "); 
//		System.out.println(" ");
//		}
       
       System.out.println("");
       System.out.println("Server:	Merge Completed. Output follows.");
       mergeArrays();
	   System.exit(0);
	   
   }
}






